

#include "staff.h"
#include "gamemanager.h"
#include "army.h"
#include "gamedatamanager.h"
#include "staffball.h"
#include "skyfall.h"
#include "log.h"
#include "messagequeue.h"
#include "CCSkeletalSprite.h"
#include "gamenodecontainer.h"
#include "fireskyfall.h"
#include "iceskyfall.h"
#include "bombskyfall.h"
#include "thunderskyfall.h"
#include "poisonskyfall.h"
#include "firefullcoverbullet.h"
#include "darkfullcoverbullet.h"
#include "poisonfullcoverbullet.h"
#include "gamescene.h"

#define __super         Unit

Staff::Staff() {

}

Staff::~Staff() {

}

void Staff::init(UnitInfo const& info, float unitScale) {
	__super::init(info, unitScale);
}

void Staff::update(float ticks) {
	__super::update(ticks);
}


void Staff::startAttack() {

}

void Staff::handleStateBirth(float ticks){
	transformState(UnitState::idle);
}

void Staff::handleStateDying(float ticks){
	if(sprite->animationIsDone()) {
		transformState(UnitState::died);
	}
}

void Staff::handleStateReload(float ticks){

}

void Staff::handleStateWalkAim(float ticks){
	if(gameScene->battleState == BattleState::standby) {
		transformState(UnitState::idle);
	} else {
		move(ticks);

		if(arrivedTargetPosition) {
			transformState(UnitState::aim);
		} else if (_timeElapsed >= attribute.castingTime) {
			transformState(UnitState::walk_attack);
		}
	}
}

void Staff::handleStateWalkReload(float ticks){

}

void Staff::handleStateAim(float ticks) {
	if(gameScene->battleState == BattleState::standby) {
		return;
	}

	if (_timeElapsed >= attribute.castingTime) {
		transformState(UnitState::attack);
	}
}

void Staff::handleStateAttack(float ticks) {
	if (sprite->animationIsDone()) {
		transformState(UnitState::aim);
	}
}

void Staff::handleStateIdle(float ticks) {
	if (sprite->animationIsDone()) {
		transformState(UnitState::aim);
	}
}

void Staff::handleStateAssign(float ticks) {
	move(ticks);

	if(arrivedTargetPosition) {
		transformState(UnitState::aim);
	}
}

void Staff::handleStateWalk(float ticks) {
	if(gameScene->battleState == BattleState::standby) {
		transformState(UnitState::idle);
	} else {
		move(ticks);

		if(arrivedTargetPosition) {
			transformState(UnitState::aim);
		} else if (_timeElapsed >= attribute.castingTime) {
			transformState(UnitState::walk_attack);
		}
	}
}

void Staff::handleStateWalkAttack(float ticks) {
	move(ticks);

	if (sprite->animationIsDone()) {
		if(arrivedTargetPosition) {
			transformState(UnitState::aim);
		} else {
			transformState(previousState);
		}
	}
}

void Staff::onEnterState(UnitState theState) {
	__super::onEnterState(theState);

	if(theState == UnitState::idle) {
		sprite->setLoopCount(1);
	}
}

void Staff::onAttack() {
	if (weapon->attackType == AttackType::single_attack) {
		Unit* enemy = findDistantOpponent();
		if (enemy) {
			auto from = sprite->getBonePositionRelativeToWorld("skeleton_head");
			auto to = enemy->sprite->getBonePositionRelativeToWorld("skeleton_head");

			Bullet *bullet = new StaffBallBullet(from, to, &attribute, gameScene);
			bullet->init();
			enemy->addBullet(bullet);
		}
	} else {
		DamageType damageType = GDM->getWeaponDamageType(attribute.projectileType);
		_DHLOG("error: staff has a wrong projectTileType in weapon.xml, weapon:%s", weapon->name.c_str());

		switch (weapon->attackType) {
			case AttackType::cast_all_units: {
				createFullCoverBullet(ourArmy, theirArmy, damageType);
				break;
			}
			case AttackType::cast_aoe_melee: {
				createSkyFallBullet(ourArmy, damageType);
		        createSkyFallBullet(theirArmy, damageType);
				break;
			}
			case AttackType::cast_squad_front_line:
			case AttackType::cast_enemy_units: {
				createSkyFallBullet(theirArmy, damageType);
				break;
			}
			default:
				break;
		}
	}

	_timeElapsed = 0;
}

void Staff::moveTo(const CCPoint& pos) {
	__super::moveTo(pos);
}

void Staff::createSkyFallBullet(Army *targetArmy, DamageType damageType) {
	SkyFallBullet* bullet = nullptr;

	switch(damageType) {
		case DamageType::fire:
			bullet = new FireSkyFallBullet(targetArmy, &attribute, gameScene);
			break;
		case DamageType::ice:
			bullet = new IceSkyFallBullet(targetArmy, &attribute, gameScene);
	        break;
		case DamageType::explosion:
			bullet = new BombSkyFallBullet(targetArmy, &attribute, gameScene);
	        break;
		case DamageType::poison:
			bullet = new PoisonSkyFallBullet(targetArmy, &attribute, gameScene);
	        break;
		case DamageType::thunder:
			bullet = new ThunderSkyFallBullet(targetArmy, &attribute, gameScene);
	        break;
		default:break;
	}

	if(bullet) {
		bullet->init();
		gameScene->addBullet(bullet);
	}
}

void Staff::createFullCoverBullet(Army *army1, Army *army2, DamageType damageType) {
	Bullet* bullet = nullptr;

	switch(damageType) {
		case DamageType::fire:
			bullet = new FireFullCoverBullet(army1, army2, &attribute, gameScene);
	        break;
		case DamageType::poison:
			bullet = new PoisonFullCoverBullet(army1, army2, &attribute, gameScene);
	        break;
		case DamageType::dark:
			bullet = new DarkFullCoverBullet(army1, army2, &attribute, gameScene);
	        break;
		default:break;
	}

	if(bullet) {
		bullet->init();
		gameScene->addBullet(bullet);
	}
}
